package bank;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import exception.KontoNichtGedecktException;

public abstract class Konto extends AbstractModel {

    private static final long serialVersionUID = 101L;

    public static final int SPARKONTO = 0;
    public static final int GIROKONTO = 1;

    public static final String PROPERTYNAME_KONTONUMMER = "kontonummer";
    public static final String PROPERTYNAME_KONTOSTAND = "kontostand";
    public static final String PROPERTYNAME_MEINE_KONTOBEWEGUNGEN = "meineKontobewegungen";

	private int kontonummer;
	private double kontostand;
	private ArrayList<Kontobewegung> meineKontobewegungen;

	public Konto() {
	}

	public Konto(int kontonummer) {
		meineKontobewegungen = new ArrayList<Kontobewegung>();
		setKontonummer(kontonummer);
		setKontostand(0);
	}

	public int getKontonummer() {
		return kontonummer;
	}

	public void setKontonummer(int aNewValue) {
	    int oldValue = getKontonummer();
		kontonummer = aNewValue;
		firePropertyChange(PROPERTYNAME_KONTONUMMER, oldValue, getKontonummer());
	}

	public double getKontostand() {
		return kontostand;
	}

	public void setKontostand(double aNewValue) {
	    double oldValue = getKontostand();
		kontostand = aNewValue;
		firePropertyChange(PROPERTYNAME_KONTOSTAND, oldValue, getKontostand());
	}

    public void einzahlen(double aBetrag) {
        einzahlen(aBetrag, new Date());
    }

    public void einzahlen(double aBetrag, Date aDate) {
        if (aBetrag < 0) {
            throw new IllegalArgumentException("Betrag muss positiv sein!");
        }
        setKontostand(getKontostand() + aBetrag);
        addKontobewegung(new Kontobewegung(aDate, aBetrag));
    }

    public void auszahlen(double aBetrag) throws KontoNichtGedecktException {
        auszahlen(aBetrag, new Date());
    }

    public void auszahlen(double aBetrag, Date aDate) throws KontoNichtGedecktException {
        setKontostand(getKontostand() - aBetrag);
        addKontobewegung(new Kontobewegung(aDate, -aBetrag));
    }

    public void addKontobewegung(Kontobewegung aKontobewegung) {
        getMeineKontobewegungen().add(aKontobewegung);
        firePropertyChange(PROPERTYNAME_KONTOSTAND, null, getMeineKontobewegungen());
    }

    /**
     * Um der Liste neue Elemente hinzuzufügen sollte {@link #addKontobewegung(Kontobewegung)}
     * aufgerufen werden.
     */
	public List<Kontobewegung> getMeineKontobewegungen() {
		return meineKontobewegungen;
	}

	public static Konto neuesKonto(int kontoNummer, int kontoArt) {
		switch (kontoArt) {
			case GIROKONTO:
				return new Girokonto(kontoNummer);

			case SPARKONTO:
				return new Sparkonto(kontoNummer);
		}
		throw new IllegalArgumentException("Falsche Kontoart: " + kontoArt);
	}

	@Override
    public boolean equals(Object aOtherObject) {
	    if (aOtherObject instanceof Konto) {
	        Konto otherKonto = (Konto) aOtherObject;
	        return getKontonummer() == otherKonto.getKontonummer();
	    }
	    return false;
	}
}
